//
// Group Memeber: Xiaodi Wu(xiaodiwu), Mac Wiltzer(maclain)
//

// This is our version of bufMap.C.
// You will fill in the code missing from each of the functions.


#include "buf.h"


// Constructor, allocate the FileMap
BufMap::BufMap()
{
  myFileMap=new FileMap;
}

// Deallocate all the maps, first level or second level
BufMap::~BufMap()
{
  FileMapItr it;
  for(it=myFileMap->begin();it!=myFileMap->end();it++)
    {
      delete (*it).second;
    }
  delete myFileMap;
}
//---------------------------------------------------------------
// insert entry, mapping (file,pageNo) to frameNo;
// returns OK if OK, BUFMAPERROR if an error occurred
//---------------------------------------------------------------

const Status BufMap::insert(File* file,
				const int pageNo,
				const unsigned int frameNo)
{
   // First Check Whether The File has a map table;
   // If not, create one; Otherwise, pass that;
   // Go to that PageMap to check;
   PageMapPtr myPageMap;
   if (myFileMap->find(file)==myFileMap->end())
   {
	   myPageMap=new PageMap;
	   (*myFileMap)[file]=myPageMap;
   }else {
        myPageMap=(*myFileMap)[file];
   }
   //
   if (myPageMap->find(pageNo)!=myPageMap->end())
   {
	   return BUFMAPERROR;
   }else (*myPageMap)[pageNo]=frameNo;
   return OK;
}


//-------------------------------------------------------------------
// Check if (file,pageNo) is currently in the buffer pool.  If so,
// return corresponding frameNo. else return BUFMAPNOTFOUND
//-------------------------------------------------------------------

const Status BufMap::lookup(File* file,
				const int pageNo,
				unsigned int & frameNo) const
{
	   // First Check whether it exists in the FileMap; Then the PageMap;
	   PageMapPtr myPageMap;
	   FileMapItr myFileMapItr=myFileMap->find(file);
           if (myFileMapItr==myFileMap->end())
	   {
               return BUFMAPNOTFOUND;
	   }else {
	     myPageMap=(*myFileMapItr).second;
	    }
		   //
	   PageMapItr it=myPageMap->find(pageNo);
	   if (it==myPageMap->end())
	   {
		   return BUFMAPNOTFOUND;
	   }else {
                     frameNo=(*it).second;
	   }
	   return OK;
}


//-------------------------------------------------------------------
// delete entry (file,pageNo) from mapping. Return OK if page was
// found. Else if the entry is not found, return BUFMAPNOTFOUND
//-------------------------------------------------------------------

const Status BufMap::remove(File* file, const int pageNo)
{
   // First Check whether it exists in the FileMap; Then the PageMap;
	   PageMapPtr myPageMap;
           FileMapItr fileIt=myFileMap->find(file);
	   if (fileIt==myFileMap->end())
	   {
          return BUFMAPNOTFOUND;
	   }else {
	     myPageMap=(*fileIt).second;
	   }
	   //
	   PageMapItr it=myPageMap->find(pageNo);

	   if (it==myPageMap->end())
	   {
		   return BUFMAPNOTFOUND;
	   }else {
		   myPageMap->erase(it);
		   if (myPageMap->empty()) 
		     {
                       delete myPageMap;
                       myFileMap->erase(fileIt); // if empty delete the second level
                     }
            }
	   return OK;
}

//-----------------------------------------------------------------
// look up the PageMap for that file*. Return BUFMAPNOTFOUND if the 
// entry is not found
//-----------------------------------------------------------------

const Status BufMap::maplookup(File* file, PageMapPtr& pageMap) const
{
  FileMapItr myFileMapItr=myFileMap->find(file);

  if (myFileMapItr==myFileMap->end())
    {
      return BUFMAPNOTFOUND;
    }
  else {
    pageMap=(*myFileMapItr).second;
  }
  
  return OK;
}
